﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using BreakOutBattles.Game;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using BreakOutBattles.Game.Events;
using BreakOutBattles.IO.Net;
using BreakOutBattles.IO;
using Lidgren.Network;
using System.Threading;
#endregion

namespace BreakOutBattles.Menus
{
    #region Enums
    public enum HorizontalChoosers
    {
        LEFT,
        RIGHT,
        NONE,
    }
    #endregion

    /// <summary>
    /// Represents the 'Create Game' menu of the game.
    /// </summary>
    public class CreateGameMenu : Menu
    {
        #region Events and delegates
        public delegate void StartGameEventHandler(StartGameEventArgs args);
        public event StartGameEventHandler StartGameEvent;
        #endregion

        #region Fields
        private HorizontalChoosers currentHorizontalChooser = HorizontalChoosers.NONE;
        private HorizontalChoosers prevHorizontalChooser = HorizontalChoosers.NONE;

        private MatchConfiguration matchConfiguation;
        private List<LevelInfo> availableLevels;
        private int selectedLevelIndex = 0;

        private Vector2 playerNamePos;
        private Vector2 roundLifesPos;
        private Vector2 thumbPos;
        private Vector2 levelNamePos;
        private Vector2 levelDescPos;
        private IOManager ioManager;

        private SpriteFont descriptionFont;
        private SpriteFont headingFont;

        private GameServer server;
        private NetworkManager networkManager;
        #endregion


        public CreateGameMenu(Microsoft.Xna.Framework.Game game, SpriteBatch spriteBatch)
            : base(game, spriteBatch)
        { }

        #region Initialization
        public override void Initialize()
        {
            base.Initialize();

            ioManager = IOManager.Instance;

            matchConfiguation = new MatchConfiguration();
            availableLevels = ioManager.GetLevelsInfo(ioManager.GetContentFolderNames(ContentFolders.LEVELS));

            descriptionFont = ioManager.LoadFont("descriptionFont");
            headingFont = ioManager.LoadFont("headingFont");

            playerNamePos = new Vector2(550, 100);
            roundLifesPos = new Vector2(550, 400);

            thumbPos = new Vector2(550, 200);
            levelNamePos = new Vector2(thumbPos.X + 180, thumbPos.Y);
            levelDescPos = new Vector2(levelNamePos.X, levelNamePos.Y + 50);

            networkManager = NetworkManager.Instance;
            server = networkManager.GameServer;
        }

        /// <summary>
        /// Creates the menu items of this menu.
        /// </summary>
        public override void CreateMenu()
        {
            menuItems.Add(new MenuItem("Nickname: ", new Vector2(350, 100), new Action(delegate { })));
            menuItems.Add(new MenuItem("<< Choose level: >> ", new Vector2(240, 250), new Action(OnSelectLevelAction)));
            menuItems.Add(new MenuItem("<< Lifes per round : >>", new Vector2(200, 400), new Action(OnSelectLifesAction)));
            menuItems.Add(new MenuItem("Start", new Vector2(550, 600), new Action(OnCreateGameAction)));
        }
        #endregion
               
        #region Menu Actions
        /// <summary>
        /// Changes the current selected level. The selections depends on the current horizontal chooser
        /// state.
        /// </summary>
        private void OnSelectLevelAction()
        {
            if (currentHorizontalChooser == HorizontalChoosers.RIGHT && prevHorizontalChooser == HorizontalChoosers.NONE)
            {
                if (selectedLevelIndex < availableLevels.Count - 1)
                {
                    selectedLevelIndex++;
                }
            }
            else if (currentHorizontalChooser == HorizontalChoosers.LEFT && prevHorizontalChooser == HorizontalChoosers.NONE)
            {
                if (selectedLevelIndex > 0)
                {
                    selectedLevelIndex--;
                }
            }

            matchConfiguation.LevelName = availableLevels[selectedLevelIndex].FileName;
        }

        /// <summary>
        ///Increases or decreases the number of lifes per round with one unit. The change depends on 
        ///the current horizontal chooser state.
        /// </summary>
        private void OnSelectLifesAction()
        {
            if (currentHorizontalChooser == HorizontalChoosers.RIGHT && prevHorizontalChooser == HorizontalChoosers.NONE)
            {
                if (matchConfiguation.LifesPerRound < MatchConfiguration.MAX_ROUND_LIFES)
                {
                    matchConfiguation.LifesPerRound++;
                }
            }
            else if (currentHorizontalChooser == HorizontalChoosers.LEFT && prevHorizontalChooser == HorizontalChoosers.NONE)
            {
                if (matchConfiguation.LifesPerRound > MatchConfiguration.MIN_ROUND_LIFES)
                {
                    matchConfiguation.LifesPerRound--;
                }
            }
        }

        /// <summary>
        /// Invoked when the player activates the Start menu option.
        /// Notifies the underlaying network manager to create a new game room and sets
        /// the current game state to JOIN_WAIT.
        /// </summary>
        private void OnCreateGameAction()
        {
            JoinManager.HostConfiguration = matchConfiguation;

            //Register the player in the join manager.
            JoinManager.HostPlayer = new Player();
            JoinManager.HostPlayer.PlayerIndex = 0;
            JoinManager.HostPlayer.Name = matchConfiguation.HostPlayerName;
            JoinManager.HostPlayer.Lifes = matchConfiguation.LifesPerRound;
            JoinManager.HostPlayer.IsRemotePlayer = false;

            //Start the game server and the client.
            server.Start();
            networkManager.GameNetClient = new GameNetClient(matchConfiguation.HostPlayerName);
            networkManager.GameNetClient.Connect();

            //Register the necesary event handler to receive join info from the server
            JoinManager.Client = networkManager.GameNetClient;
            networkManager.GameNetClient.ClientConfigReceived += JoinManager.SecondaryConfigurationReceived;

            GameState.CurrentState = GameStates.PLAYER_JOIN_WAIT;            
        }
        #endregion

        #region Input Handling
        /// <summary>
        /// Handles user interaction with the menu.
        /// </summary>
        protected override void HandleInput(GameTime gameTime)
        {
            base.HandleInput(gameTime);
            HandleAlphabeticKeyPressed();
            HandleHorizontalChoosers();
        }

        /// <summary>
        /// Checks if the player is trying to interact with the current menu option,
        /// using the left/right buttons and handles such a situation, if an action
        /// is available for that option.
        /// </summary>
        private void HandleHorizontalChoosers()
        {
            if (KeyPressed(Keys.Left))
            {
                currentHorizontalChooser = HorizontalChoosers.LEFT;
                menuItems[currentMenuIndex].Invoke();
            }
            else if (KeyReleased(Keys.Left) && currentHorizontalChooser != HorizontalChoosers.NONE)
            {
                currentHorizontalChooser = HorizontalChoosers.NONE;
            }

            if (KeyPressed(Keys.Right))
            {
                currentHorizontalChooser = HorizontalChoosers.RIGHT;
                menuItems[currentMenuIndex].Invoke();
            }
            else if (KeyReleased(Keys.Right) && currentHorizontalChooser != HorizontalChoosers.NONE)
            {
                currentHorizontalChooser = HorizontalChoosers.NONE;
            }
                        
            prevHorizontalChooser = currentHorizontalChooser;
        }

        /// <summary>
        /// Checks if an alphabetical key has been pressed, if so, the character mapped
        /// to the pressed key will be appended to the current player nickname.
        /// </summary>
        private void HandleAlphabeticKeyPressed()
        {
            if (currentMenuIndex == 0)
            {
                foreach (Keys key in keyboardState.GetPressedKeys())
                {
                    if (KeyPressed(key) && IsAlphabeticalKey(key))
                    {
                        if (key == Keys.OemPeriod)
                        {
                            matchConfiguation.HostPlayerName += '.';
                        }
                        else
                        {
                            matchConfiguation.HostPlayerName += (char)key;
                        }
                    }
                }

                if (KeyPressed(Keys.Back))
                {
                    if (matchConfiguation.HostPlayerName.Length > 0)
                    {
                        matchConfiguation.HostPlayerName = matchConfiguation.HostPlayerName.Substring(0, matchConfiguation.HostPlayerName.Length - 1);
                    }
                }
            }
        }
        #endregion

        /// <summary>
        /// Renders the menu.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            spriteBatch.DrawString(font, matchConfiguation.HostPlayerName, playerNamePos, Color.Red);
            spriteBatch.DrawString(font, matchConfiguation.LifesPerRound + string.Empty, roundLifesPos, Color.Red);

            spriteBatch.Draw(availableLevels[selectedLevelIndex].Thumbnail, thumbPos, Color.White);
            spriteBatch.DrawString(headingFont, availableLevels[selectedLevelIndex].Name, levelNamePos, Color.Red);
            spriteBatch.DrawString(descriptionFont, availableLevels[selectedLevelIndex].Description, levelDescPos, Color.White);
        }
    }
}
